package com.zzyl.service.impl;

import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.LoginDto;
import com.zzyl.dto.UserDto;
import com.zzyl.entity.User;
import com.zzyl.entity.UserRole;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.RoleUserMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.properties.SecurityConfigProperties;
import com.zzyl.service.UserService;
import com.zzyl.utils.JwtUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.UserVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserServiceimpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleUserMapper roleUserMapper;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Value("${zzyl.framework.jwt.base64-encoded-secret-key}")
    private String secretKey;

    @Value("${zzyl.framework.jwt.ttl}")
    private Integer ttl;

    @Autowired
    private SecurityConfigProperties securityConfigProperties;

    @Override
    public PageResponse page(UserDto userDto, Integer pageNum, Integer pageSize) {
        if(pageNum <= 0){
            pageNum = 1;
        }
        if(pageSize <= 0){
            pageSize = 10;
        }
        PageHelper.startPage(pageNum,pageSize);
        userDto.setDeptNo(NoProcessing.processString(userDto.getDeptNo()));
        Page<UserVo> page = userMapper.page(userDto);
        page.stream().map(u->{
            Set<String> idlist = roleUserMapper.selectId(u.getId());
            Set<String> namelist = roleUserMapper.selectName(u.getId());
            u.setRoleVoIds(idlist);
            u.setRoleLabels(namelist);
            return u;
        }).collect(Collectors.toList());
        PageResponse<UserVo> of = PageResponse.of(page, UserVo.class);
        return of;
    }

    @Override
    public void addUser(UserDto userDto) throws CloneNotSupportedException {
        User user = userDto.clone();
        String password = BCrypt.hashpw("888itcast.CN764%...", BCrypt.gensalt());
        user.setPassword(password);
        userMapper.addUser(user);
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userDto.getRoleVoIds().forEach(u->{
            userRole.setRoleId(Long.parseLong(u));
            roleUserMapper.addUserRole(userRole);
        });
    }

    @Override
    public void update(UserDto userDto) throws CloneNotSupportedException {
        User user = userDto.clone();
        userMapper.update(user);
        roleUserMapper.delete(userDto.getId());
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userDto.getRoleVoIds().forEach(u->{
            userRole.setRoleId(Long.parseLong(u));
            roleUserMapper.addUserRole(userRole);
        });

    }

    @Override
    public void updateStatus(Long id, String status) {
        User user = User.builder()
                .dataState(status)
                .build();
        user.setId(id);

        userMapper.updateStatus(user);
    }

    @Override
    public UserVo getByName(String name) {
        UserVo userVo = userMapper.getByName(name);
        return userVo;
    }

    @Override
    public void delete(Long id) {
        User user = new User();
        user.setId(id);
        userMapper.delete(user);
    }

    @Override
    public void resetPassword(Long id) {
        String hashpw = BCrypt.hashpw("888itcast.CN764%...", BCrypt.gensalt());
        User user = User.builder().password(hashpw).build();
        user.setId(id);
        userMapper.resetPassword(user);
    }

    @Override
    public UserVo login(LoginDto loginDto) {
        if(ObjectUtil.isEmpty(loginDto) || ObjectUtil.isEmpty(loginDto.getUsername()) || ObjectUtil.isEmpty(loginDto.getPassword())){
            throw new BaseException(BasicEnum.LOGIN_DATA_NOT_NULL);
        }
        User user = userMapper.selectByName(loginDto.getUsername());

        if(ObjectUtil.isEmpty(user)){
            throw new BaseException(BasicEnum.LOGIN_USERDATA_NOT_NULL);
        }
        if(SuperConstant.DATA_STATE_1.equals(user.getDataState())){
            throw new BaseException(BasicEnum.LOGIN_STATUS_ERROR);
        }
        boolean checkpw = BCrypt.checkpw(loginDto.getPassword(), user.getPassword());
        if(!checkpw){
            throw new BaseException(BasicEnum.LOGIN_PASSWORD_ERROR);
        }
        UserVo vo = new UserVo();
        BeanUtils.copyProperties(user,vo);
        vo.setPassword("");
        vo.setCreateTime(null);
        vo.setUpdateTime(null);
        Map<String,Object> data = new HashMap<>();
        data.put("currentUser",vo);

        String jwt = JwtUtil.createJWT(secretKey, ttl, data);
        vo.setUserToken(jwt);

        List<String> pathId = userMapper.selectPathById(user.getId());
        Collections.addAll(pathId, securityConfigProperties.getPublicAccessUrls().toArray(new String[0]));

        redisTemplate.opsForValue().set(SuperConstant.USER_RESOURCE+user.getId(), JSONUtil.toJsonStr(pathId));

        return vo;
    }
}
